#include "WiFiIno_flash.h"
#include "esp_err.h"
#include "wifi_apstation.h"

static const char* TAG = "NVSino";
char SSID_BUFF[64] = "56666";
char PASSWORD_BUFF[64] = "5555555555" ;


//关于wifi信息的结构体 内含ssid和password
WiFiIno_Type_t WiFiIno = {
    .ssid = SSID_BUFF,
    .password = PASSWORD_BUFF,
};


void write_nvs_byte(const char* namespace, const char* key, int8_t VALUE)
{
    nvs_handle_t nvs_handle;

    esp_err_t err = nvs_open(namespace, NVS_READWRITE, &nvs_handle);
    if (err!= ESP_OK) {
        printf("Error opening NVS: %d\n", err);
    }
    
    err = nvs_set_i8(nvs_handle, key, VALUE);
    if (err!= ESP_OK) {
        printf("Error writing to NVS: %d\n", err);
    }    

    err = nvs_commit(nvs_handle);
    if (err!= ESP_OK) {
        printf("Error committing to NVS: %d\n", err);
    } 

     nvs_close(nvs_handle);
}


void read_nvs_byte(const char* namespace,const char* key, int8_t *VALUE)
{
    nvs_handle_t nvs_handle;

    //ESP_LOGI(TAG, "读取NVS之前的WiFiInoCfgStatus: %d", WiFiInoCfgStatus);

    esp_err_t err;
    nvs_handle_t nvs_handle_check;
    err = nvs_open(namespace, NVS_READONLY, &nvs_handle_check);
    if (err == ESP_ERR_NVS_NOT_FOUND) {
        // 命名空间不存在，进行初始化操作
        // 可以在这里记录日志，提醒用户命名空间不存在需要初始化
        // ESP_LOGE("NVS", "Namespace does not exist. Initializing...");
        // 关闭用于检查的句柄，避免资源泄漏
        nvs_close(nvs_handle_check);
    } else if (err == ESP_OK) {
        // 命名空间存在，关闭用于检查的句柄，然后进行正常读写操作
        nvs_close(nvs_handle_check);
        ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
        ESP_ERROR_CHECK(nvs_get_i8(nvs_handle, key, VALUE));
        nvs_close(nvs_handle);
    } else {
        // 其他错误情况，记录错误并处理
        ESP_LOGE("NVS", "Error opening namespace for check: %s", esp_err_to_name(err));
        // 关闭用于检查的句柄，避免资源泄漏
        nvs_close(nvs_handle_check);
        // 根据具体情况，可能需要返回错误码或者采取其他措施
        // return err;
    }
}



static size_t read_nvs_str(const char* namespace,const char* key,char* value,int maxlen)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret_val = ESP_FAIL;
    size_t required_size = 0;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret_val = nvs_get_str(nvs_handle, key, NULL, &required_size);
    if(ret_val == ESP_OK && required_size <= maxlen)
    {
        nvs_get_str(nvs_handle,key,value,&required_size);
    }
    else
        required_size = 0;
    nvs_close(nvs_handle);
    return required_size;
}










/** 写入int类型到NVS中
 * @param namespace NVS命名空间
 * @param key NVS键值
 * @param value 需要写入的值
 * @return ESP_OK or ESP_FAIL
*/
static esp_err_t write_nvs_int(const char* namespace, const char* key,  int32_t value)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    
    ret = nvs_set_i32(nvs_handle, key, value);
    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret;
}




/** 从nvs中读取int类型
 * @param namespace NVS命名空间
 * @param key 要读取的键值
 * @param value 读到的值
 * @param maxlen 外部存储数组的最大值
*/
static size_t read_nvs_int(const char* namespace,const char* key, int32_t* value)
{
    nvs_handle_t nvs_handle;
    esp_err_t err;

    err = nvs_open(namespace, NVS_READWRITE, &nvs_handle);
    if (err == ESP_ERR_NVS_NOT_FOUND) {
        // 命名空间不存在，记录日志提醒
        ESP_LOGE("NVS", "int Namespace does not exist.");
    } else if (err == ESP_OK) {
        err = nvs_get_i32(nvs_handle, key, value);
        if (err!= ESP_OK) {
            // 处理读取失败的情况
            ESP_LOGE("NVS", "Error getting int value: %s", esp_err_to_name(err));
        }
        nvs_close(nvs_handle);
    } else {
        // 其他错误情况，记录错误
        ESP_LOGE("NVS", "Error opening namespace: %s", esp_err_to_name(err));
    }
    return err;
}





/** 写入int64类型到NVS中
 * @param namespace NVS命名空间
 * @param key NVS键值
 * @param value 需要写入的值
 * @return ESP_OK or ESP_FAIL
*/
static esp_err_t write_nvs_int64(const char* namespace, const char* key,  int64_t value)
{
    nvs_handle_t nvs_handle; 
    esp_err_t ret;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    
    ret = nvs_set_i64(nvs_handle, key, value);
    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret;
}

static size_t read_nvs_int64(const char* namespace,const char* key, int64_t* value)
{
    nvs_handle_t nvs_handle;
    esp_err_t err;

    err = nvs_open(namespace, NVS_READWRITE, &nvs_handle);
    if (err == ESP_ERR_NVS_NOT_FOUND) {
        // 命名空间不存在，记录日志提醒
        ESP_LOGE("NVS", "int Namespace does not exist.");
    } else if (err == ESP_OK) {
        err = nvs_get_i64(nvs_handle, key, value);
        if (err!= ESP_OK) {
            // 处理读取失败的情况
            ESP_LOGE("NVS", "Error getting int value: %s", esp_err_to_name(err));
        }
        nvs_close(nvs_handle);
    } else {
        // 其他错误情况，记录错误
        ESP_LOGE("NVS", "Error opening namespace: %s", esp_err_to_name(err));
    }
    return err;
}









/** 写入值到NVS中（字符数据）
 * @param namespace NVS命名空间
 * @param key NVS键值
 * @param value 需要写入的值
 * @return ESP_OK or ESP_FAIL
*/
static esp_err_t write_nvs_str(const char* namespace, const char* key, const char* value)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    
    ret = nvs_set_str(nvs_handle, key, value);
    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret;
}


/** 擦除nvs区中某个键
 * @param namespace NVS命名空间
 * @param key 要读取的键值
 * @return 错误值
*/
static esp_err_t erase_nvs_key(const char* namespace,const char* key)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret_val = ESP_FAIL;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret_val = nvs_erase_key(nvs_handle,key);
    ret_val = nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret_val;
}

/** 写入值到NVS中(字节数据)
 * @param namespace NVS命名空间
 * @param key NVS键值
 * @param value 需要写入的值
 * @return ESP_OK or ESP_FAIL
*/
static esp_err_t write_nvs_blob(const char* namespace,const char* key,uint8_t* value,size_t len)
{
    nvs_handle_t nvs_handle;
    esp_err_t ret;
    ESP_ERROR_CHECK(nvs_open(namespace, NVS_READWRITE, &nvs_handle));
    ret = nvs_set_blob(nvs_handle, key, value,len);
    nvs_commit(nvs_handle);
    nvs_close(nvs_handle);
    return ret;
}

//用void函数封一层，static无法直接声明，这是之前写的，不想改了
void Write_nvs_blob(const char* namespace,const char* key,uint8_t* value,size_t len)
{
    write_nvs_blob(namespace, key, value, len);
}

void Erase_nvs_key(const char* namespace,const char* key)
{
    erase_nvs_key(namespace, key);
}




void Read_nvs_int(const char* namespace, const char* key, int32_t *value)
{
    read_nvs_int(namespace, key, value);
}
void Write_nvs_int(const char* namespace, const char* key, int32_t value)
{
    write_nvs_int(namespace, key, value);
}


void Read_nvs_int64(const char* namespace, const char* key, int64_t *value)
{
    read_nvs_int64(namespace, key, value);
}
void Write_nvs_int64(const char* namespace, const char* key, int64_t value)
{
    write_nvs_int64(namespace, key, value);
}



void Write_nvs_str(const char* namespace,const char* key,const char* value)
{
    write_nvs_str(namespace, key, value);
}

void Read_nvs_str(const char* namespace,const char* key,char* value,int maxlen)
{
    size_t len = 0;

    len =read_nvs_str(NVS_WiFi_Ino_NAMESPACE, NVS_SSID_KEY, SSID_BUFF, 64);
    if(len)
        ESP_LOGI(TAG, "Read WiFi SSID:%s", SSID_BUFF);
    else
        ESP_LOGI(TAG, "Read WiFi SSID fail,please perform nvs_erase_key and try again");

    //打印读出来的SSID密码数据
    ESP_LOGI(TAG, "Read SSID_BUFF:%s", SSID_BUFF);

}

/**从nvs中获取wifi信息
 * @param 无
 * @return 无
 */
void GetWiFiInoFromNvs()
{
    size_t len = 0;

    //write_nvs_byte(NVS_WiFiInoCfgStatus_NAMESPACE, NVS_WiFiInoCfgStatus);

    read_nvs_byte(NVS_WiFiInoCfgStatus_NAMESPACE, NVS_WiFiInoCfgStatus, &WiFiInoCfgStatus);  //读取NVS中的WiFiInoCfgStatus

    ESP_LOGI(TAG, "读取完之后WiFiInoCfgStatus的值: %d", WiFiInoCfgStatus);

    read_nvs_byte(NVS_OTACfgStatus_NAMESPACE, NVS_OTACfgStatus, &OTA_FINISH_OR_FAIL); //读取NVS中的OTA_FINISH_OR_FAIL

    // ESP_LOGI(TAG, "读取完之后OTA_FINISH_OR_FAIL的值: %d", OTA_FINISH_OR_FAIL);

    // if(OTA_FINISH_OR_FAIL == 1){
    //     ESP_LOGI(TAG, "程序升级完成，设备已完成重启");
    // }

    //读取NVS_WiFi_Ino_NAMESPACE命名空间中的SSID键值
    len =read_nvs_str(NVS_WiFi_Ino_NAMESPACE, NVS_SSID_KEY, SSID_BUFF, 64);
    if(len)
        ESP_LOGI(TAG, "Read WiFi SSID:%s", SSID_BUFF);
    else
        ESP_LOGI(TAG, "Read WiFi SSID fail,please perform nvs_erase_key and try again");
        

    //读取NVS_WiFi_Ino_NAMESPACE命名空间中的PASSWORD键值
    len = read_nvs_str(NVS_WiFi_Ino_NAMESPACE, NVS_PASSWORD_KEY, PASSWORD_BUFF, 64);
    if(len)
        ESP_LOGI(TAG, "Read WiFi PASSWORD:%s", PASSWORD_BUFF);
    else
        ESP_LOGI(TAG, "Read WiFi PASSWORD fail, please perform nvs_erase_key and try again");

    //读取NVS_DEV_Id_NAMESPACE命名空间中的NVS_DEV_ID_KEY键值
    len = read_nvs_str(NVS_DEV_Id_NAMESPACE, NVS_DEV_ID_KEY, LocationBatIno.device_id, 16);
    if(len){
        ESP_LOGI(TAG, "Read LocationBatIno.device_id:%s", LocationBatIno.device_id);
        //将读取到的字符串形式的设备id转换成纯数值Dev_id
        int result = sscanf(LocationBatIno.device_id, "%" SCNd64, &LocationBatIno.Dev_id);
        ESP_LOGE(TAG, "LocationBatIno.Dev_id:%" PRId64"", LocationBatIno.Dev_id);
    }

    else
        ESP_LOGI(TAG, "Read LocationBatIno.device_id fail, please perform nvs_erase_key and try again");


    // 读取NVS_Box_Ino_NAMESPACE命名空间中的NVS_BUILDING_KEY键值
    len = read_nvs_int(NVS_Box_Ino_NAMESPACE, NVS_BUILDING_KEY, &LocationBatIno.building_id);
    if(len)
        ESP_LOGI(TAG, "Read LocationBatIno.building_id:%ld", LocationBatIno.building_id);
    else
        ESP_LOGI(TAG, "Read LocationBatIno.building_id fail, please perform nvs_erase_key and try again");
    ESP_LOGI(TAG, "设备所处的楼栋LocationBatIno.building_id:%ld", LocationBatIno.building_id);
    

    //读取NVS_Box_Ino_NAMESPACE命名空间中的NVS_FLOOR_KEY键值
    len = read_nvs_int(NVS_Box_Ino_NAMESPACE, NVS_FLOOR_KEY, &LocationBatIno.floor_id);
    if(len)
        ESP_LOGI(TAG, "Read LocationBatIno.floor_id:%ld", LocationBatIno.floor_id);
    else
        ESP_LOGI(TAG, "Read LocationBatIno.floor_id fail, please perform nvs_erase_key and try again");
    ESP_LOGI(TAG, "设备所处的楼层LocationBatIno.floor_id:%ld", LocationBatIno.floor_id);


    //读取NVS_Box_Ino_NAMESPACE命名空间中的NVS_ROOM_KEY 键值
    len = read_nvs_int(NVS_Box_Ino_NAMESPACE, NVS_ROOM_KEY , &LocationBatIno.room_id);
    if(len)
        ESP_LOGI(TAG, "Read LocationBatIno.room_id:%ld", LocationBatIno.room_id);
    else
        ESP_LOGI(TAG, "Read LocationBatIno.room_id fail, please perform nvs_erase_key and try again");
    ESP_LOGI(TAG, "LocationBatIno.room_id:%ld", LocationBatIno.room_id);


    //读取NVS_Box_Ino_NAMESPACE命名空间中的NVS_ROOM_POSTION_KEY 键值
    len = read_nvs_int(NVS_Box_Ino_NAMESPACE, NVS_ROOM_POSTION_KEY , &LocationBatIno.device_location_id);
    if(len)
        ESP_LOGI(TAG, "Read LocationBatIno.device_location_id:%ld", LocationBatIno.device_location_id);
    else
        ESP_LOGI(TAG, "Read LocationBatIno.device_location_id fail, please perform nvs_erase_key and try again");
    ESP_LOGI(TAG, "LocationBatIno.device_location_id:%ld", LocationBatIno.device_location_id);

    //读取NVS_Box_Ino_NAMESPACE命名空间中的 NVS_BOX_TYPE_KEY 键值
    len = read_nvs_int(NVS_Box_Ino_NAMESPACE,  NVS_BOX_TYPE_KEY , &LocationBatIno.device_type_id);
    if(len)
        ESP_LOGI(TAG, "Read LocationBatIno.device_type_id:%ld", LocationBatIno.device_type_id);
    else
        ESP_LOGI(TAG, "Read LocationBatIno.device_type_id fail, please perform nvs_erase_key and try again");
    ESP_LOGI(TAG, "LocationBatIno.device_type_id:%ld", LocationBatIno.device_type_id);


    //WIFI信息未配置完成
    if( !WiFiInoCfgStatus )
    {        
        // WiFiIno.ssid = SSID_BUFF;
        // WiFiIno.password = PASSWORD_BUFF;
    }
    else  //密码校验成功，写入NVS中
    {
        len = read_nvs_str(NVS_WiFi_Ino_NAMESPACE, NVS_SSID_KEY, WiFiIno.ssid, 64);
        if(len)
            ESP_LOGI(TAG, "Read WiFi SSID:%s", WiFiIno.ssid);
        else
            ESP_LOGI(TAG, "Read WiFi SSID fail,please perform nvs_erase_key and try again");
     

        len = read_nvs_str(NVS_WiFi_Ino_NAMESPACE, NVS_PASSWORD_KEY, WiFiIno.password, 64);
        if(len)
            ESP_LOGI(TAG, "Read WiFi PASSWORD:%s", WiFiIno.password);
        else
            ESP_LOGI(TAG, "Read WiFi PASSWORD fail, please perform nvs_erase_key and try again");
    }
}
